package com.atguigu.tingshu.account.service.impl;
import java.util.Date;

import com.atguigu.tingshu.account.mapper.UserAccountDetailMapper;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.google.common.collect.Maps;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.account.mapper.UserAccountMapper;
import com.atguigu.tingshu.account.service.UserAccountService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.account.UserAccount;
import com.atguigu.tingshu.model.account.UserAccountDetail;
import com.atguigu.tingshu.vo.account.AccountLockResultVo;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {

	@Autowired
	private UserAccountMapper userAccountMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserAccountDetailMapper userAccountDetailMapper;

    @Override
    public BigDecimal getAvailableAmount() {
        Long userId = AuthContextHolder.getUserId();
        LambdaQueryWrapper<UserAccount> queryWrapper = new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getUserId, userId);
        UserAccount userAccount = userAccountMapper.selectOne(queryWrapper);
        if (userAccount == null){
            return new BigDecimal("0.00");
        }
        return  userAccount.getAvailableAmount();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<AccountLockResultVo> checkAndLockAccount(AccountLockVo accountLockVo) {
        // 获取属性值
        BigDecimal amount = accountLockVo.getAmount();
        Long userId = accountLockVo.getUserId();
        String content = accountLockVo.getContent();
        String orderNo = accountLockVo.getOrderNo();
        String userAccountResultKey = "user:account:data" + orderNo;
        // 解决幂等性（OpenFeign的重试机制导致的重复发送请求）
        String openFeignKey = "feign:retry:msg:container" + orderNo;
        List<String> range = redisTemplate.opsForList().range(openFeignKey, 0, -1);
        if (range != null && range.contains(orderNo)) {
            return Result.build(null, ResultCodeEnum.ACCOUNT_LOCK_REPEAT);
        }
//        Boolean aBoolean = redisTemplate.opsForValue().setBit(openFeignKey, userId, true);
//        if (aBoolean){
//            return Result.build(null, ResultCodeEnum.ACCOUNT_LOCK_REPEAT);
//        }
        try {
            Long aLong = redisTemplate.opsForList().leftPush(openFeignKey, orderNo);
            if (aLong == 1L){
                // 校验余额与锁定账户
                int count = userAccountMapper.opsDbCheckAndLockAccount(userId,amount);
                if (count == 0 ){
                    throw new GuiguException(201,"账户余额不足,请充值");
                }
                // 准备AccountLockResultVo对象
                AccountLockResultVo accountLockResultVo = new AccountLockResultVo();
                accountLockResultVo.setUserId(userId);
                accountLockResultVo.setAmount(amount);
                accountLockResultVo.setContent(content);
                //将AccountLockResultVo对象存储到Redis(解锁和真正扣减余额操作方便)
                redisTemplate.opsForValue().set(userAccountResultKey, JSONObject.toJSONString(accountLockResultVo));
                // 保存账户的流水
                this.logs(userId, "锁定:" + content, "1202", amount, orderNo);
                return Result.ok(accountLockResultVo);
            }else {
                return Result.build(null, ResultCodeEnum.ACCOUNT_LOCK_REPEAT);
            }
        } catch (Exception e) {
            //同一个订单正常干完不能删（别人进来不能操作）只有我操作期间出现了异常 才允许让别人操作
            redisTemplate.delete(openFeignKey);
            return Result.build(null, ResultCodeEnum.ACCOUNT_LOCK_ERROR);
        }
    }

    public void logs(Long userId, String title, String tradeType, BigDecimal amount, String orderNo) {
        UserAccountDetail userAccountDetail = new UserAccountDetail();
        userAccountDetail.setUserId(userId);
        userAccountDetail.setTitle(title);
        userAccountDetail.setTradeType(tradeType);
        userAccountDetail.setAmount(amount);
        userAccountDetail.setOrderNo(orderNo);
        userAccountDetailMapper.insert(userAccountDetail);
    }
}
